using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Http;
using Microsoft.IdentityModel.Tokens;
using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using Urs.Data.Domain.Users;
using Urs.Data.Domain.Configuration;
using Urs.Services.Users;

namespace Urs.Services.Authentication
{
    public partial class FormsAuthenticationService : IAuthenticationService
    {
        private readonly IUserService _userService;
        private readonly UserSettings _userSettings;
        private readonly IHttpContextAccessor _httpContextAccessor;

        private User _cachedUser;

        public FormsAuthenticationService(IUserService userService, UserSettings userSettings,
            IHttpContextAccessor httpContextAccessor)
        {
            this._httpContextAccessor = httpContextAccessor;
            this._userService = userService;
            this._userSettings = userSettings;
        }


        public virtual async void SignIn(User user, bool isPersistent)
        {
            if (user == null)
                throw new ArgumentNullException(nameof(user));

            var claims = new List<Claim>();

            claims.Add(new Claim(ClaimTypes.NameIdentifier, user.Id.ToString(), ClaimValueTypes.Integer32, "UrShop"));

            var userIdentity = new ClaimsIdentity(claims, "Authentication");
            var userPrincipal = new ClaimsPrincipal(userIdentity);

            var authenticationProperties = new AuthenticationProperties
            {
                IsPersistent = isPersistent,
                IssuedUtc = DateTime.UtcNow
            };

            await _httpContextAccessor.HttpContext.SignInAsync("Authentication", userPrincipal, authenticationProperties);

            _cachedUser = user;
        }

        public virtual string JwtSignIn(User user, string securityKey, int expiresdays, string issuer, string audience)
        {
            var claims = new Claim[]
            {
               new Claim(ClaimTypes.NameIdentifier,user.UserGuid.ToString()),
            };

            var key = new SymmetricSecurityKey(System.Text.Encoding.UTF8.GetBytes(securityKey));
            var expires = DateTime.Now.AddDays(expiresdays);
            var token = new JwtSecurityToken(
                        issuer: issuer,
                        audience: audience,
                        claims: claims,
                        notBefore: DateTime.Now,
                        expires: expires,
                        signingCredentials: new SigningCredentials(key, SecurityAlgorithms.HmacSha256));

            string jwtToken = new JwtSecurityTokenHandler().WriteToken(token);
            return jwtToken;
        }

        public virtual async void SignOut()
        {
            _cachedUser = null;
            await _httpContextAccessor.HttpContext.SignOutAsync("Authentication");
        }

        public virtual User GetAuthenticatedUser()
        {
            if (_cachedUser != null)
                return _cachedUser;

            var authenticateResult = _httpContextAccessor.HttpContext.AuthenticateAsync("Authentication").Result;
            if (!authenticateResult.Succeeded)
                return null;

            User user = null;
            var usernameClaim = authenticateResult.Principal.FindFirst(claim => claim.Type == ClaimTypes.NameIdentifier
                && claim.Issuer.Equals("UrShop", StringComparison.InvariantCultureIgnoreCase));
            var userId = 0;
            if (usernameClaim != null && int.TryParse(usernameClaim.Value, out userId))
                user = _userService.GetUserById(userId);

            if (user == null || !user.Active || user.Deleted || !user.IsRegistered())
                return null;

            _cachedUser = user;

            return _cachedUser;

        }

    }
}